home *** CD-ROM | disk | FTP | other *** search
- /* Parse command line, set up command arguments Unix-style, and call function.
- * Note: argument is modified (delimiters are overwritten with nulls)
- * Improved error handling by Brian Boesch of Stanford University
- */
- #include <stdio.h>
- #include <ctype.h>
- #include "global.h"
- #include "proc.h"
- #include "cmdparse.h"
-
- static char * near
- stringparse(line)
- char *line;
- {
- char *cp = line;
- unsigned long num;
-
- while ( *line != '\0' && *line != '\"' ) {
- if ( *line == '\\' ) {
- line++;
- switch ( *line++ ) {
- case 'n':
- *cp++ = '\n';
- break;
- case 't':
- *cp++ = '\t';
- break;
- case 'v':
- *cp++ = '\v';
- break;
- case 'b':
- *cp++ = '\b';
- break;
- case 'r':
- *cp++ = '\r';
- break;
- case 'f':
- *cp++ = '\f';
- break;
- case 'a':
- *cp++ = '\a';
- break;
- case '\\':
- *cp++ = '\\';
- break;
- case '\?':
- *cp++ = '\?';
- break;
- case '\'':
- *cp++ = '\'';
- break;
- case '\"':
- *cp++ = '\"';
- break;
- case 'x':
- num = strtoul( --line, &line, 16 );
- *cp++ = (char) num;
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- num = strtoul( --line, &line, 8 );
- *cp++ = (char) num;
- break;
- case '\0':
- return NULLCHAR;
- default:
- *cp++ = *(line - 1);
- break;
- };
- } else {
- *cp++ = *line++;
- }
- }
-
- if ( *line == '\"' )
- line++; /* skip final quote */
- *cp = '\0'; /* terminate string */
- return line;
- }
-
- int
- cmdparse(cmds,line,p)
- struct cmds cmds[];
- char *line;
- void *p;
- {
- struct cmds *cmdp;
- char *argv[NARG], *cp, **pargv;
- int argc, i;
-
- /* Remove cr/lf */
- rip(line);
-
- for(argc = 0;argc < NARG;argc++)
- argv[argc] = NULLCHAR;
-
- for(argc = 0;argc < NARG; ){
- int qflag = FALSE;
-
- /* Skip leading white space */
- while(*line == ' ' || *line == '\t')
- line++;
- if(*line == '\0')
- break;
- /* Check for quoted token */
- if(*line == '"'){
- line++; /* Suppress quote */
- qflag = TRUE;
- }
- argv[argc++] = line; /* Beginning of token */
-
- if(qflag){
- /* Find terminating delimiter */
- if((line = stringparse(line)) == NULLCHAR){
- return -1;
- }
- } else {
- /* Find space or tab. If not present,
- * then we've already found the last
- * token.
- */
- if((cp = strchr(line,' ')) == NULLCHAR
- && (cp = strchr(line,'\t')) == NULLCHAR){
- break;
- }
- *cp++ = '\0';
- line = cp;
- }
- }
- if (argc < 1) { /* empty command line */
- argc = 1;
- argv[0] = "";
- }
- /* Lines beginning with "#" are comments */
- if(argv[0] == NULLCHAR || argv[0][0] == '#')
- return 0;
-
- /* Look up command in table; prefix matches are OK */
- for(cmdp = cmds;cmdp->name != NULLCHAR;cmdp++){
- if(strncmp(argv[0],cmdp->name,strlen(argv[0])) == 0)
- break;
- }
- if(cmdp->name == NULLCHAR) {
- if(cmdp->argc_errmsg != NULLCHAR)
- tprintf("%s\n",cmdp->argc_errmsg);
- return -1;
- } else {
- if(argc < cmdp->argcmin) {
- /* Insufficient arguments */
- tprintf("Usage: %s\n",cmdp->argc_errmsg);
- return -1;
- } else {
- if(cmdp->stksize == 0){
- return (*cmdp->func)(argc,argv,p);
- } else {
- /* Make private copy of argv and args,
- * spawn off subprocess and return.
- */
- pargv = (char **)cxallocw(argc,sizeof(char *));
- for(i=0;i<argc;i++)
- pargv[i] = strxdup(argv[i]);
- newproc(cmdp->name,cmdp->stksize,
- (void (*)())cmdp->func,argc,pargv,p,1);
- return(0);
- }
- }
- }
- }
-
- /* Call a subcommand based on the first token in an already-parsed line */
- int
- subcmd(tab,argc,argv,p)
- struct cmds tab[];
- int argc;
- char *argv[];
- void *p;
- {
- struct cmds *cmdp;
- char **pargv;
- int i, found = 0;
-
- /* Strip off first token and pass rest of line to subcommand */
- if(argc < 1) {
- tputs("SUBCMD - Don't know what to do\n");
- return -1;
- }
- if(argc > 1) {
- argc--;
- argv++;
- for(cmdp = tab; cmdp->name != NULLCHAR; cmdp++) {
- if(strncmp(argv[0],cmdp->name,strlen(argv[0])) == 0){
- found = 1;
- break;
- }
- }
- }
- if(!found) {
- tputs("available subcommands:\n");
- for(i = 0, cmdp = tab; cmdp->name != NULLCHAR; cmdp++, i = (i+1)%5)
- tprintf("%-15.15s%s",cmdp->name,(i == 4) ? "\n" : "");
-
- if(i)
- tputs("\n");
- return -1;
- }
- if(argc < cmdp->argcmin){
- if(cmdp->argc_errmsg != NULLCHAR)
- tprintf("Usage: %s\n",cmdp->argc_errmsg);
- return -1;
- }
- if(cmdp->stksize == 0){
- return (*cmdp->func)(argc,argv,p);
- } else {
- /* Make private copy of argv and args */
- pargv = (char **)cxallocw(argc,sizeof(char *));
- for(i=0;i<argc;i++)
- pargv[i] = strxdup(argv[i]);
- newproc(cmdp->name,cmdp->stksize,
- (void (*)())cmdp->func,argc,pargv,p,1);
- return(0);
- }
- }
-
- /* Subroutine for setting and displaying boolean flags */
- int
- setbool(var,label,argc,argv)
- int *var;
- char *label;
- int argc;
- char *argv[];
- {
- struct boolcmd {
- char *str; /* Token */
- int val; /* Value */
- } Boolcmds[] = {
- "y", 1, /* Synonyms for "true" */
- "yes", 1,
- "true", 1,
- "on", 1,
- "1", 1,
- "set", 1,
- "enable", 1,
-
- "n", 0, /* Synonyms for "false" */
- "no", 0,
- "false", 0,
- "off", 0,
- "0", 0,
- "clear", 0,
- "disable", 0,
- NULLCHAR
- };
- struct boolcmd *bc;
-
- if(argc < 2){
- tprintf("%s: %s\n",label,*var ? "on":"off");
- return 0;
- }
- for(bc = Boolcmds; bc->str != NULLCHAR; bc++) {
- if(strcmpi(argv[1],bc->str) == 0){
- *var = bc->val;
- return 0;
- }
- }
- tputs("Valid options:");
- for(bc = Boolcmds;bc->str != NULLCHAR;bc++)
- tprintf(" %s",bc->str);
- tputs("\n");
- return 1;
- }
-
- /* Subroutine for setting and displaying long variables */
- int
- setlong(var,label,argc,argv)
- long *var;
- char *label;
- int argc;
- char *argv[];
- {
- if(argc < 2)
- tprintf("%s: %ld\n",label,*var);
- else
- *var = atol(argv[1]);
-
- return 0;
- }
-
- /* Subroutine for setting and displaying short variables */
- int
- setshort(var,label,argc,argv)
- unsigned short *var;
- char *label;
- int argc;
- char *argv[];
- {
- if(argc < 2)
- tprintf("%s: %u\n",label,*var);
- else
- *var = atoi(argv[1]);
-
- return 0;
- }
-
- /* Subroutine for setting and displaying integer variables */
- int
- setint(var,label,argc,argv)
- int *var;
- char *label;
- int argc;
- char *argv[];
- {
- if(argc < 2)
- tprintf("%s: %u\n",label,*var);
- else
- *var = atoi(argv[1]);
-
- return 0;
- }
-
- /* Subroutine for setting and displaying int variables (with range check) */
- int
- setintrc(var, label, argc, argv, minval, maxval)
- int16 *var;
- char *label;
- int argc;
- char *argv[];
- int minval;
- int16 maxval;
- {
- int tmp;
-
- if (argc < 2)
- tprintf("%s: %u\n", label, *var);
- else {
- tmp = atoi(argv[1]);
- if (isalpha(*argv[1]) || tmp < minval || tmp > maxval) {
- tprintf("%s must be %i..%i\n", label, minval, maxval);
- return 1;
- }
- *var = (int16)tmp;
- }
- return 0;
- }